﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;

using DnPakExplorer.Forms;

namespace DnPakExplorer {
	class DnPlayerUtil {
		public const string PLAYE_DOC_PATH = @".\Data\player.xml";

		private static XmlDocument mPlayerDoc;

		private static XmlDocument PlayerDoc {
			get {
				if (mPlayerDoc == null) {
					mPlayerDoc = new XmlDocument();
					mPlayerDoc.Load(PLAYE_DOC_PATH);
				}
				return mPlayerDoc;
			}
		}

		/// <summary>
		/// 通过角色名加载用户创建的角色
		/// </summary>
		/// <param name="characerName">要加载的角色名</param>
		/// <returns>如果没有找到指定名称的角色，返回null</returns>
		public static Character LoadCharacter(string characerName) {
			XmlDocument doc = PlayerDoc;
			XmlNode characterNode = doc.SelectSingleNode("/Player/Character[@name=\""+characerName+"\"]");
			if (characterNode != null) {
				XmlAttributeCollection attr = characterNode.Attributes;
				Character Character = new Character(
					int.Parse(attr.GetNamedItem("job").InnerText),
					int.Parse(attr.GetNamedItem("level").InnerText),
					int.Parse(attr.GetNamedItem("heroLevel").InnerText));
				Character.Name = attr.GetNamedItem("name").InnerText;
				XmlNode attrNode = attr.GetNamedItem("appellation");
				if (attrNode != null) {
					Appellation app = new Appellation();
					app.AppellationId = int.Parse(attrNode.InnerText);
					Character.Appellation = app;
				}
				foreach (XmlNode itemNode in characterNode.SelectNodes("./Bag/Item")) {
					IUserItem item = ParseItemXmlNode(itemNode);
					Character.BagPanel.AddItem(item);
				}
				foreach (XmlNode slotNode in characterNode.SelectNodes("./Equipement/Slot")) {
					((ItemSlot)((EquipmentPanel)Character.EquipmentPanel).GetSlot<ItemSlot>(int.Parse(slotNode.Attributes.GetNamedItem("slotId").InnerText)))
						.Item = ParseItemXmlNode(slotNode.ChildNodes[0]);

				}
				foreach (XmlNode skillNode in characterNode.SelectNodes("./Skills/Skill")) {
					Skill skill = DnResourceUtil.LoadSkill(int.Parse(skillNode.Attributes["id"].InnerText));
					skill.Level = int.Parse(skillNode.Attributes["level"].InnerText);
					Character.SkillNanel.AddSkill(skill);

				}
				return Character;
			} else
				return null;
		}


		/// <summary>
		/// 保存角色，只有保存到文件才会永久保存角色信息
		/// </summary>
		/// <param name="character">要保存的指定角色</param>
		/// <param name="saveToFile">是否同时将更改（包括之前的）保存到文件</param>
		public static void SaveCharacter(Character character, bool saveToFile) {
			XmlDocument doc = PlayerDoc;

			#region Character Node
			XmlNode characterNode = doc.SelectSingleNode("/Player/Character[@name=\""+character.Name+"\"]");
			if (characterNode == null) {
				XmlNode playerNode = doc.SelectSingleNode("/Player");
				if (playerNode == null) {
					playerNode = doc.CreateNode(XmlNodeType.Element, "Player", null);
					doc.AppendChild(playerNode);
				}
				doc.CreateNode(XmlNodeType.Element, "Character", null);
				playerNode.AppendChild(characterNode);
			}

			characterNode.RemoveAll();
			XmlAttribute attr = null;

			attr = doc.CreateAttribute("name");
			attr.InnerText = character.Name;
			characterNode.Attributes.Append(attr);

			attr = doc.CreateAttribute("level");
			attr.InnerText = character.Level.ToString();
			characterNode.Attributes.Append(attr);

			attr = doc.CreateAttribute("job");
			attr.InnerText = character.JobId.ToString();
			characterNode.Attributes.Append(attr);

			attr = doc.CreateAttribute("heroLevel");
			attr.InnerText = character.HeroLevel.ToString();
			characterNode.Attributes.Append(attr);

			if (character.Appellation != null) {
				attr = doc.CreateAttribute("appellation");
				attr.InnerText = character.Appellation.AppellationId.ToString();
				characterNode.Attributes.Append(attr);
			}

			#endregion

			#region Bag Node
			XmlElement bagEl = doc.CreateElement("Bag");
			BagPanel bag = (BagPanel)character.BagPanel;
			for (int i=0; i<bag.BagSize; i++) {
				IUserItem item = bag[i];
				if (item != null) {
					bagEl.AppendChild(CreateItemXmlElememt(item, "Item", doc));
				} else {
					bagEl.AppendChild(doc.CreateElement("EmptySlot"));
				}
			}
			characterNode.AppendChild(bagEl);
			#endregion

			#region Equipement Node
			XmlElement equipEl = doc.CreateElement("Equipement");
			EquipmentPanel equipe = (EquipmentPanel)character.EquipmentPanel;
			foreach (IEquipmentProperyable euip in equipe.ItemSlots) {
				IItemSlot slot = euip as IItemSlot;
				if (slot != null && slot.Item != null) {
					XmlElement slotEl = doc.CreateElement("Slot");
					slotEl.SetAttribute("slotId", slot.Id.ToString());
					slotEl.AppendChild(CreateItemXmlElememt(slot.Item, "Item", doc));
					equipEl.AppendChild(slotEl);
				}
			}
			characterNode.AppendChild(equipEl);
			#endregion

			#region Skill　Node
			XmlElement skillsEl = doc.CreateElement("Skills");
			SkillPanel skillPanel = character.SkillNanel;
			for (int i=0; i<skillPanel.SkillCount; i++) {
				skillsEl.AppendChild(CreateSkillElement(skillPanel[i], "Skill", doc));
			}
			characterNode.AppendChild(skillsEl);
			#endregion

			if (saveToFile) {
				doc.Save(PLAYE_DOC_PATH);
			}
		}

		private static XmlElement CreateSkillElement(Skill skill, string name, XmlDocument doc){
			XmlElement skillEl = doc.CreateElement(name);
			skillEl.SetAttribute("id", skill.SkillID.ToString());
			skillEl.SetAttribute("level", skill.Level.ToString());
			return skillEl;
		}

		/// <summary>
		/// 创建用于保存物品的XmlElement
		/// </summary>
		/// <param name="item">对应物品</param>
		/// <param name="name">XmlElement的名称</param>
		/// <param name="doc">目标XmlDocument</param>
		/// <returns></returns>
		private static XmlElement CreateItemXmlElememt(IUserItem item, string name, XmlDocument doc) {
			XmlElement itemEl = doc.CreateElement(name);
			itemEl.SetAttribute("id", item.id.ToString());
			itemEl.SetAttribute("appliedEnchantLevel", item.appliedEnchantLevel.ToString());
			itemEl.SetAttribute("appliedPotential1", item.appliedPotential1.ToString());
			itemEl.SetAttribute("appliedPotential2", item.appliedPotential2.ToString());
			List<DragonJewelSlot> djs = item.AppliedSlotsList;
			if (djs != null) {
				foreach (DragonJewelSlot slot in djs) {
					if (slot.Item != null) {
						itemEl.AppendChild(CreateItemXmlElememt(slot.Item, "DragonJewel", doc));
					}else{
						itemEl.AppendChild(doc.CreateElement("EmptySlot"));
					}
				}
			}
			if (item.AppliedImprintingSlot != null && item.AppliedImprintingSlot.Item != null) {
				itemEl.AppendChild(CreateItemXmlElememt(item.AppliedImprintingSlot.Item, "Imprinting", doc));
			}
			return itemEl;
		}

		/// <summary>
		/// 通过XmlNode解析出保存的物品
		/// </summary>
		private static IUserItem ParseItemXmlNode(XmlNode itemNode) {
			IUserItem item = DnResourceUtil.LoadEmptyUserItem(int.Parse(itemNode.Attributes.GetNamedItem("id").InnerText));
			if (item != null) {
				XmlNode attrNode = null;
				if (item.enchantId>0 && (attrNode = itemNode.Attributes.GetNamedItem("appliedEnchantLevel")) != null) {
					item.appliedEnchantLevel = int.Parse(attrNode.InnerText);
				}
				if (item.typeParam1>0 && (attrNode = itemNode.Attributes.GetNamedItem("appliedPotential1")) != null) {
					item.appliedPotential1 = int.Parse(attrNode.InnerText);
				}
				if (item.typeParam2>0 && (attrNode = itemNode.Attributes.GetNamedItem("appliedPotential2")) != null) {
					item.appliedPotential2 = int.Parse(attrNode.InnerText);
				}
				if (item.imprintingType != ImprintingType.None && (attrNode = itemNode.Attributes.GetNamedItem("appliedImprintId")) != null) {
					int id = int.Parse(attrNode.InnerText);
					if (id > 0) {
						IUserItem impriting = DnResourceUtil.LoadEmptyUserItem(id);
						if (item.AppliedImprintingSlot != null 
							&& item.AppliedImprintingSlot.Item == null
							&& item.AppliedImprintingSlot.CanEquip(impriting)) {
							item.AppliedImprintingSlot.Item = impriting;
						}
					}
				}
				foreach (XmlNode node in itemNode.ChildNodes) {
					if (node.Name == "DragonJewel") {
						IUserItem dragonJewel = ParseItemXmlNode(node);
						List<DragonJewelSlot> djs = item.AppliedSlotsList;
						if(djs != null){
							foreach (DragonJewelSlot slot in djs) {
								if (slot.Item == null && slot.CanEquip(dragonJewel)) {
									slot.Item = dragonJewel;
								}
							}
						}
					} else if (node.Name == "Imprinting") {
						IUserItem impriting = ParseItemXmlNode(node);
						if (item.AppliedImprintingSlot != null 
							&& item.AppliedImprintingSlot.Item == null
							&& item.AppliedImprintingSlot.CanEquip(impriting)) {
							item.AppliedImprintingSlot.Item = impriting;
						} 
					}
				}
			}
			return item;
		}

	
		public static void CreateCharacter(CharacterInfo info) {
			XmlDocument doc = PlayerDoc;
			XmlNode characterNode = doc.SelectSingleNode("/Player/Character[@name="+info.name+"]");
			if (characterNode == null) {
				XmlElement characterEl = doc.CreateElement("Character");
				characterEl.SetAttribute("name", info.name);
				characterEl.SetAttribute("level", info.level.ToString());
				characterEl.SetAttribute("job", info.job.ToString());
				characterEl.SetAttribute("heroLevel", info.heroLevel.ToString());

				doc.SelectSingleNode("/Player").AppendChild(characterEl);
				doc.Save(PLAYE_DOC_PATH);
			} else
				throw new Exception("已经存在同名角色。");
		}


		/// <summary>
		/// 弹出UI界面，让用户选择或是创建一个角色
		/// </summary>
		public static Character SelectOrCreateICharacter {
			get {
				List<CharacterInfo> list = AllCharacters;
				if (list != null && list.Count>0) {
					string name = null;
					CharacterSelectorForm form = new CharacterSelectorForm();
					form.SetCharacterInfos(list.ToArray());
					if (form.ShowDialog() == System.Windows.Forms.DialogResult.OK) {
						name = form.SelectedCharacterInfo.name;
						Util.LoadTables();
						return LoadCharacter(name);
					}
				} else {
					CharacterEditorForm form = new CharacterEditorForm();
					if (form.ShowDialog() == System.Windows.Forms.DialogResult.OK) {
						try {
							CreateCharacter(form.CharacterInfo);
							return LoadCharacter(form.CharacterInfo.name);
						} catch (Exception e) {
							System.Windows.Forms.MessageBox.Show(e.Message);
						}
					}
				}
				return null;
			}
		}

		/// <summary>
		/// 获取所以的角色信息
		/// </summary>
		public static List<CharacterInfo> AllCharacters {
			get {
				XmlDocument doc = PlayerDoc;
				XmlNodeList characterNodes = doc.SelectNodes("/Player/Character");
				if (characterNodes != null) {
					List<CharacterInfo> characters = new List<CharacterInfo>(characterNodes.Count);
					foreach (XmlNode characterNode in characterNodes) {
						XmlAttributeCollection attr = characterNode.Attributes;
						CharacterInfo characterInfo = new CharacterInfo();
						characterInfo.job = int.Parse(attr.GetNamedItem("job").InnerText);
						characterInfo.level = int.Parse(attr.GetNamedItem("level").InnerText);
						characterInfo.name = attr.GetNamedItem("name").InnerText;
						characterInfo.heroLevel = int.Parse(attr.GetNamedItem("heroLevel").InnerText);
						characters.Add(characterInfo);
					}
					return characters;
				}
				return null;
			}
		}

		public static Character CurrentCharacter { get; set; }
	}

	/// <summary>
	/// 角色信息
	/// </summary>
	public class CharacterInfo {
		public string name;
		public int level;
		public int job;
		public int heroLevel;
	}
}
